package xaj.scc.ast;

import java.util.Iterator;
import java.util.List;

import polyglot.ast.Node;
import polyglot.ext.jl.ast.Node_c;
import polyglot.util.CodeWriter;
import polyglot.util.CollectionUtil;
import polyglot.util.Position;
import polyglot.util.TypedList;
import polyglot.visit.NodeVisitor;
import polyglot.visit.PrettyPrinter;

public class SyntaxDeclarationInsertion_c extends Node_c implements SyntaxDeclarationInsertion {

	private boolean isExtended;
	private String nonTerminalExtended;
	private List<String> using;
	private List<Production> productions;
	
	public SyntaxDeclarationInsertion_c(Position pos, List<String> using,
			List<Production> productions) {
		super(pos);
		this.using = using;
		this.productions = productions;
		isExtended = false;
	}

	public SyntaxDeclarationInsertion_c(Position pos, String nonTerminal, List<String> using,
			List<Production> productions) {
		super(pos);
		this.using = using;
		this.productions = productions;
		this.nonTerminalExtended = nonTerminal;
		isExtended = true;
	}

	public String getNonTerminalExtended() {
		if(! isExtended) {
			//@ TODO Lançar um erro nesse ponto é mais adequado. 
			return null;
		}
		return nonTerminalExtended;
	}

	public List<Production> getProductions() {
		return productions;
	}

	public List<String> getUsing() {
		return using;
	}

	public boolean isExtended() {
		return isExtended;
	}

	public SyntaxDeclarationInsertion setNonTerminalExtended(String nonTerminal) {
		SyntaxDeclarationInsertion_c n = (SyntaxDeclarationInsertion_c) copy();
		n.nonTerminalExtended = nonTerminal;
		return n;
	}

	public SyntaxDeclarationInsertion setProductions(List<Production> productions) {
		SyntaxDeclarationInsertion_c n = (SyntaxDeclarationInsertion_c) copy();
		n.productions = TypedList.copyAndCheck(productions, Production.class, true);
		return n;
	}

	public SyntaxDeclarationInsertion setUsing(List<String> using) {
		SyntaxDeclarationInsertion_c n = (SyntaxDeclarationInsertion_c) copy();
		n.using = TypedList.copyAndCheck(productions, String.class, true);
		return n;
	}

	protected SyntaxDeclarationInsertion_c reconstruct(List<Production> productions) {
        if(!CollectionUtil.equals(productions, this.productions)) {
        	SyntaxDeclarationInsertion_c node = (SyntaxDeclarationInsertion_c) copy();
        	node.productions = TypedList.copyAndCheck(productions, Production.class, true);
        	return node;
        }
        return this;
    }
	
	public Node visitChildren(NodeVisitor v) {
		List<Production> productions = visitList(this.productions, v);
		return reconstruct(productions);
	}
	
	public void prettyPrint(CodeWriter w, PrettyPrinter tr) {
		w.newline(4);
		w.begin(0);
		w.write("@grammar" + (isExtended ? " extends " + nonTerminalExtended : ""));
		if(!using.isEmpty()) {
			w.write(" using ");
			Iterator<String> it = using.iterator();
			String s = it.next();
			w.write(s);
			while(it.hasNext()) {
				s = it.next();
				w.write(", " + s);
			}
		}
		w.write(" {");
		w.newline(4);
		w.begin(0);
		for(Production p : productions) {
			p.prettyPrint(w, tr);
		}
		w.end();
		w.newline();
		w.write("}");
		w.end();
	}
	
	@Override
	public void accept(Visitor v) {
		v.visitSyntaxDeclarationInsertion(this);
	}
	
}